﻿using System;
using System.Collections.Concurrent;
using System.Threading;

namespace MyLib
{
    /// <summary>
    /// 可以构建一个Long运行的线程 而不是在当前线程处理逻辑 避免Room创建的线程太繁忙了
    /// Actor需要构建两种 IO型Actor 和 CPU型Actor 
    /// TODO:CPU型Actor 需要独立的Long线程来执行
    /// CPU型Actor 一个 Actor 绑定一个线程
    /// </summary>
    public class ActorSynchronizationContext : SynchronizationContext
    {
        private readonly SynchronizationContext _subContext;
        private readonly ConcurrentQueue<Action> _pending = new ConcurrentQueue<Action>();
        private int _pendingCount;

        public ActorSynchronizationContext(SynchronizationContext context = null)
        {
            this._subContext = context ?? new SynchronizationContext();
        }

        /// <summary>
        /// 当前没有在执行的逻辑
        /// _subContext.Post 从线程池中找一个线程来执行当前的业务逻辑，防止卡死当前主线程
        /// ThreadPool.QueueUserWorkItem
        /// 当前有执行逻辑，则将后续逻辑压入到等待队列中
        /// 适合IO密集型逻辑，需要频繁等待IO操作结束，线程不断切换，不适合CPU密集逻辑
        /// </summary>
        /// <param name="d"></param>
        /// <param name="state"></param>
        public override void Post(SendOrPostCallback d, object state)
        {
            if (d == null) {
                throw new ArgumentNullException("SendOrPostCallback");
            }
            _pending.Enqueue(() => d(state));
            if (Interlocked.Increment(ref _pendingCount) == 1)
            {
                try
                {
                    _subContext.Post(Consume, null); 
                }
                catch (Exception exp)
                {
                    LogHelper.LogUnhandleException(exp.ToString());
                }
            }
        }

        /// <summary>
        /// 后续逻辑执行仍然在当前线程池 线程上处理
        /// </summary>
        /// <param name="state"></param>
        private void Consume(object state)
        {
            var surroundContext = Current;
            SetSynchronizationContext(this);
            do
            {
                Action a;
                _pending.TryDequeue(out a);
                try
                {
                    a.Invoke();
                }
                catch (Exception exp)
                {
                    //Debug.LogError(exp.ToString());
                    LogHelper.LogUnhandleException(exp.ToString());
                }
            } while (Interlocked.Decrement(ref _pendingCount) > 0);
            SetSynchronizationContext(surroundContext);
        }

        /// <summary>
        /// Send也是按照异步逻辑来执行
        /// 本身无法支持
        /// 需要后面自己还原到SyncContext下面去Post执行
        /// </summary>
        /// <param name="d"></param>
        /// <param name="state"></param>
        public override void Send(SendOrPostCallback d, object state)
        {
            LogHelper.Log2("SendCallback:"+d);
            //throw new NotSupportedException();
            //在当前Context下面send执行用于 CancelToken 直接执行后面自己Post
            //确保实在MainLoop下调用
            if (SynchronizationContext.Current != this) throw new ArgumentException("SynchronizeContext Not Right");
            d(state);
            /*
            if(d == null)
            {
                throw new ArgumentNullException("ActorSync:Send");
            }
            //还是按照Send来执行吧
            _pending.Enqueue(() => d(state));
            if (Interlocked.Increment(ref _pendingCount) == 1)
            {
                try
                {
                    _subContext.Post(Consume, null);
                }
                catch (Exception exp)
                {
                    LogHelper.LogUnhandleException(exp.ToString());
                }
            }
            */
        }
        /// <summary>
        /// TaskAwaiter 需要调用该函数来复制
        /// </summary>
        /// <returns></returns>
        public override SynchronizationContext CreateCopy()
        {
            return this;
        }
    }
}

